/*
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.matezk.dms.controller.tencent;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.matezk.dms.things.mapper.DeviceMapper;
import cn.matezk.dms.things.mapper.PersonFlowMapper;
import cn.matezk.dms.things.model.entity.*;
import cn.matezk.dms.things.service.DeviceService;
import cn.matezk.dms.things.service.EventService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.iotexplorer.v20190423.models.CallDeviceActionSyncRequest;
import com.tencentcloudapi.iotexplorer.v20190423.models.CallDeviceActionSyncResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;

@Tag(name = "腾讯云")
@RestController
@RequestMapping("tencent")
@Slf4j
public class TencentController {
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private EventService eventService;
    @Autowired
    private PersonFlowMapper personFlowMapper;

    @SaIgnore
    @GetMapping(value = {"", "event", "property", "state"})
    @Operation(summary = "腾讯云", description = "接口验证")
    public void check(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String echo = request.getHeader("Echostr");
        try (PrintWriter out = response.getWriter()) {
            out.print(echo);
            response.flushBuffer();
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    @SaIgnore
    @PostMapping("property")
    @Operation(summary = "腾讯云", description = "物模型上报")
    public void property(@RequestBody JSONObject property) {
        log.info(property.toStringPretty());
        String productId = property.getStr("productid");
        String deviceName = property.getStr("devicename");
        String deviceId = productId.concat("/").concat(deviceName);
        DeviceDO device = deviceMapper.selectOne(new QueryWrapper<DeviceDO>().eq("device_id", deviceId));
        if (ObjectUtil.isNull(device))
            return;
        if (ObjectUtil.isNull(device.getDesired()))
            device.setDesired(JSONUtil.createObj());
        if (ObjectUtil.isNull(device.getReported()))
            device.setReported(JSONUtil.createObj());
        if (!property.containsKey("payload"))
            return;
        JSONObject payload = property.getJSONObject("payload");
        if (!payload.containsKey("params"))
            return;
        JSONObject params = payload.getJSONObject("params");
        if (ObjectUtil.isNull(device.getReported()))
            device.setReported(JSONUtil.createObj());
        if (ObjectUtil.isNull(device.getDesired()))
            device.setDesired(JSONUtil.createObj());

        if (params.containsKey("mode")) {
            device.getReported().set("mode", params.getInt("mode"));
        }
        if (params.containsKey("fid")) {
            device.getReported().set("fid", JSONUtil.toBean(params.getJSONObject("fid"), Fid.class));
        }
        if (params.containsKey("standby")) {
            device.getReported().set("standby", JSONUtil.toBean(params.getJSONObject("standby"), Standby.class));
        }
        if (params.containsKey("guard")) {
            device.getReported().set("guard", JSONUtil.toBean(params.getJSONObject("guard"), Guard.class));
        }
        deviceMapper.updateByPrimaryKeySelective(device);
        JSONObject desired = JSONUtil.createObj();
        if (ObjectUtil.isNotNull(device.getDesiredMode()) && ObjectUtil.notEqual(device.getDesiredMode(), device
            .getReportedMode())) {
            desired.set("mode", Integer.valueOf(device.getDesiredMode()));
        }
        if (ObjectUtil.isNotNull(device.getDesiredFid()) && ObjectUtil.notEqual(device.getDesiredFid(), device
            .getReportedFid())) {
            desired.set("fid", device.getDesiredFid());
        }
        if (ObjectUtil.isNotNull(device.getDesiredStandby()) && ObjectUtil.notEqual(device.getDesiredStandby(), device
            .getReportedStandby())) {
            desired.set("standby", device.getDesiredStandby());
        }
        if (ObjectUtil.isNotNull(device.getDesiredGuard()) && ObjectUtil.notEqual(device.getDesiredGuard(), device
            .getReportedGuard())) {
            desired.set("guard", device.getDesiredGuard());
        }
        if (!desired.isEmpty()) {
            try {
                deviceService.control(productId, deviceName, desired.toString());
            } catch (TencentCloudSDKException e) {
                log.error(e.getMessage());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        // 上报客流量
        if (params.containsKey("flow")) {
            JSONObject flow = params.getJSONObject("flow");
            PersonFlowDO flowDO = new PersonFlowDO();
            flowDO.setDeviceId(deviceId);
            flowDO.setFlow(flow.getInt("num"));
            flowDO.setDataTime(LocalDateTimeUtil.parse(flow.getStr("time"), DatePattern.NORM_DATETIME_PATTERN));
            personFlowMapper.insert(flowDO);
        }
    }

    @SaIgnore
    @PostMapping("state")
    @Operation(summary = "腾讯云", description = "上下线推送")
    public void state(@RequestBody JSONObject object) {
        log.info(object.toStringPretty());
    }

    @SaIgnore
    @PostMapping("event")
    @Operation(summary = "腾讯云", description = "事件推送")
    public void event(@RequestBody JSONObject object) {
        String deviceCode = object.getStr("productid").concat("/").concat(object.getStr("devicename"));
        Date eventTime = object.getDate("timemills");
        JSONObject payload = object.getJSONObject("payload");
        if (payload.containsKey("events")) {
            JSONArray events = payload.getJSONArray("events");
            List<JSONObject> tEvents = JSONUtil.toList(events, JSONObject.class);
            for (JSONObject ev : tEvents) {
                try {
                    EventDO eventDO = new EventDO();
                    eventDO.setEventTime(eventTime);
                    eventDO.setEventId(payload.getStr("eventId"));
                    eventDO.setParams(payload.getJSONObject("params"));
                    log.info("设备{}触发{}事件", deviceCode, ev.getStr("eventId"));
                    eventService.handle(eventDO);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            }
        } else {
            try {
                log.info("设备{}触发{}事件", deviceCode, payload.getStr("eventId"));
                EventDO eventDO = new EventDO();
                eventDO.setEventTime(eventTime);
                eventDO.setEventId(payload.getStr("eventId"));
                eventDO.setParams(payload.getJSONObject("params"));
                log.info("设备{}触发{}事件", deviceCode, payload.getStr("eventId"));
                eventService.handle(eventDO);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    }

    @PostMapping("action")
    @Operation(summary = "腾讯云", description = "行为调用")
    public CallDeviceActionSyncResponse callAction(@RequestBody CallDeviceActionSyncRequest request) throws TencentCloudSDKException {
        return deviceService.callAction(request);
    }
}
